{
 "cells": [
  {
   "cell_type": "code",
   "id": "dcec0dcad5bc3b5a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-18T03:00:17.536319Z",
     "start_time": "2025-07-18T03:00:08.198821Z"
    }
   },
   "source": [
    "from modelscope import AutoModelForCausalLM\n",
    "from modelscope import AutoTokenizer\n",
    "\n",
    "model_name = \"Qwen/Qwen3-0.6B\"\n",
    "model = AutoModelForCausalLM.from_pretrained(model_name)\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_name)"
   ],
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/dadudu/miniconda3/envs/mini-gpt/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading Model from https://www.modelscope.cn to directory: /Users/dadudu/.cache/modelscope/hub/models/Qwen/Qwen3-0.6B\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-07-18 11:00:11,134 - modelscope - INFO - Target directory already exists, skipping creation.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading Model from https://www.modelscope.cn to directory: /Users/dadudu/.cache/modelscope/hub/models/Qwen/Qwen3-0.6B\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-07-18 11:00:17,342 - modelscope - INFO - Target directory already exists, skipping creation.\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "cell_type": "code",
   "id": "b723256f3b44a694",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-18T03:00:19.157549Z",
     "start_time": "2025-07-18T03:00:19.154475Z"
    }
   },
   "source": [
    "data = [\n",
    "    {\"Q\": \"你是谁\", \"A\": \"我是大都督周瑜的AI助手\"}\n",
    "]"
   ],
   "outputs": [],
   "execution_count": 3
  },
  {
   "cell_type": "code",
   "id": "dad97ba67b6cd2a4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-18T03:00:28.336708Z",
     "start_time": "2025-07-18T03:00:28.328171Z"
    }
   },
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "lora_prompt_template = \"\"\"\n",
    "<|im_start|>user\n",
    "{question}<|im_end|>\n",
    "<|im_start|>assistant\n",
    "<think>\n",
    "\n",
    "</think>\n",
    "{answer}\n",
    "<|im_end|>\"\"\"\n",
    "\n",
    "\n",
    "class ZhouyuDataset(Dataset):\n",
    "    def __init__(self, data, max_length=128):\n",
    "        self.encodings = []\n",
    "        for qa in data:\n",
    "            text = lora_prompt_template.format(question=qa[\"Q\"], answer=qa[\"A\"])\n",
    "            encoded = tokenizer(\n",
    "                text,\n",
    "                max_length=max_length,\n",
    "                padding='max_length',\n",
    "                truncation=True,\n",
    "                return_tensors='pt'\n",
    "            )\n",
    "            input_ids = encoded['input_ids'].squeeze()\n",
    "            self.encodings.append(input_ids)\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.encodings)\n",
    "\n",
    "    def __getitem__(self, idx):\n",
    "        return self.encodings[idx]\n",
    "\n",
    "\n",
    "dataset = ZhouyuDataset(data)"
   ],
   "outputs": [],
   "execution_count": 4
  },
  {
   "cell_type": "code",
   "id": "30248c4637f68ccd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-18T03:00:46.756526Z",
     "start_time": "2025-07-18T03:00:46.753226Z"
    }
   },
   "source": [
    "from transformers import DataCollatorForLanguageModeling\n",
    "\n",
    "# 创建数据收集器\n",
    "data_collator = DataCollatorForLanguageModeling(\n",
    "    tokenizer=tokenizer,\n",
    "    mlm=False  # 使用CLM（因果语言模型）\n",
    ")"
   ],
   "outputs": [],
   "execution_count": 6
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "43ab3f403bda5a7f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-17T13:40:22.791620Z",
     "start_time": "2025-07-17T13:40:22.789644Z"
    }
   },
   "outputs": [],
   "source": [
    "# !pip install peft"
   ]
  },
  {
   "cell_type": "code",
   "id": "f574c3617ff84d25",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-18T03:00:49.071393Z",
     "start_time": "2025-07-18T03:00:48.874788Z"
    }
   },
   "source": [
    "from peft import LoraConfig, get_peft_model, TaskType\n",
    "\n",
    "lora_config = LoraConfig(\n",
    "    task_type=TaskType.CAUSAL_LM,\n",
    "    r=2,\n",
    "    target_modules=[\"q_proj\", \"k_proj\", \"v_proj\"]\n",
    ")\n",
    "\n",
    "# 应用LoRA\n",
    "lora_model = get_peft_model(model, lora_config)\n",
    "lora_model.print_trainable_parameters()  # 查看可训练参数"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "trainable params: 401,408 || all params: 596,451,328 || trainable%: 0.0673\n"
     ]
    }
   ],
   "execution_count": 7
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "9d23efe865e1c102",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-17T13:40:56.558012Z",
     "start_time": "2025-07-17T13:40:22.869283Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "No label_names provided for model class `PeftModelForCausalLM`. Since `PeftModel` hides base models input arguments, if label_names is not given, label_names can't be set automatically within `Trainer`. Note that empty label_names list will be used instead.\n",
      "/Users/dadudu/miniconda3/envs/mini-gpt/lib/python3.10/site-packages/torch/utils/data/dataloader.py:683: UserWarning: 'pin_memory' argument is set as true but not supported on MPS now, then device pinned memory won't be used.\n",
      "  warnings.warn(warn_msg)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      \n",
       "      <progress value='150' max='150' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      [150/150 00:42, Epoch 150/150]\n",
       "    </div>\n",
       "    <table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       " <tr style=\"text-align: left;\">\n",
       "      <th>Step</th>\n",
       "      <th>Training Loss</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>10</td>\n",
       "      <td>6.888900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>20</td>\n",
       "      <td>5.536500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>30</td>\n",
       "      <td>4.274200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>40</td>\n",
       "      <td>3.328500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>50</td>\n",
       "      <td>2.496600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>60</td>\n",
       "      <td>1.797400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>70</td>\n",
       "      <td>1.219500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>80</td>\n",
       "      <td>0.907000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>90</td>\n",
       "      <td>0.727400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>100</td>\n",
       "      <td>0.643000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>110</td>\n",
       "      <td>0.610300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>120</td>\n",
       "      <td>0.596700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>130</td>\n",
       "      <td>0.589600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>140</td>\n",
       "      <td>0.585600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>150</td>\n",
       "      <td>0.583700</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table><p>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "TrainOutput(global_step=150, training_loss=2.0523267300923664, metrics={'train_runtime': 43.6353, 'train_samples_per_second': 3.438, 'train_steps_per_second': 3.438, 'total_flos': 50788093132800.0, 'train_loss': 2.0523267300923664, 'epoch': 150.0})"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from transformers import Trainer, TrainingArguments\n",
    "\n",
    "# 训练配置\n",
    "training_args = TrainingArguments(\n",
    "    output_dir=\"./huggingface_lora_qwen3\",\n",
    "    per_device_train_batch_size=4,\n",
    "    num_train_epochs=150,\n",
    "    logging_steps=10\n",
    ")\n",
    "\n",
    "# 创建Trainer\n",
    "trainer = Trainer(\n",
    "    model=lora_model,\n",
    "    args=training_args,\n",
    "    train_dataset=dataset,\n",
    "    data_collator=data_collator\n",
    ")\n",
    "\n",
    "# 开始训练\n",
    "trainer.train()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "399b10bb3f9e97c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-17T13:41:11.089714Z",
     "start_time": "2025-07-17T13:40:56.609631Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<|im_start|>user\n",
      "你是谁<|im_end|>\n",
      "<|im_start|>assistant\n",
      "<think>\n",
      "\n",
      "</think>\n",
      "\n",
      "我是大都督周瑜的AI助手<|im_end|>\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "\n",
    "prompt = \"你是谁\"\n",
    "messages = [\n",
    "    {\"role\": \"user\", \"content\": prompt}\n",
    "]\n",
    "text = tokenizer.apply_chat_template(\n",
    "    messages,\n",
    "    tokenize=False,\n",
    "    add_generation_prompt=True,\n",
    "    enable_thinking=False\n",
    ")\n",
    "\n",
    "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"mps\")\n",
    "model_inputs = tokenizer([text], return_tensors=\"pt\")\n",
    "model_inputs = model_inputs.to(device)\n",
    "generated_ids = lora_model.generate(**model_inputs, max_new_tokens=32768)\n",
    "content = tokenizer.decode(generated_ids[0])\n",
    "print(content)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
